package org.tinygroup.dbclustercase;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.lang.math.RandomUtils;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;

public class DbclusterTest extends AbstractJavaSamplerClient {

	private static final int DEFAULT_BATCH_SIZE = 1000;
	private static TestInitial init;
	static {
		init = TestInitial.getInstance();
		init.init();
	}

	private String isShard;
	private String testMode;
	private int batchNum;
	

	private static volatile int executeTimes=0;

	private static AtomicInteger atomicInteger = new AtomicInteger(0);
	
	private static final String BIGDATA = "大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过大是大非放到方法过";

	
	@Override
	public void setupTest(JavaSamplerContext context) {
		super.setupTest(context);
		this.isShard = context.getParameter("isShard", "true");// 是否分片
		this.testMode = context.getParameter("testMode", "batchInsert");// 测试方法
		this.batchNum = context.getIntParameter("batchNum");// 测试方法
		if (testMode.equals("batchInsert")) {
			Connection connection = null;
			try {
				if (isShard.equals("true")) {
					connection = init.getDbclusterConnection();
				} else {
					connection = init.getCommonConnection();
				}
				deleteOperate("delete from t_order", connection);
				deleteOperate("delete from t_order_item", connection);
			} catch (SQLException e) {
				throw new RuntimeException(e);
			} finally {
				try {
					connection.close();
				} catch (SQLException e) {
				}
			}
		}

	}

	@Override
	public void teardownTest(JavaSamplerContext context) {
		super.teardownTest(context);
		init.getDataSource().shutdown();
		init.getDruidDatasource().close();
	}

	public SampleResult runTest(JavaSamplerContext context) {

		SampleResult sr = new SampleResult();
		sr.setSampleLabel("Java请求哦");
		Connection connection = null;
		try {
			if (isShard.equals("true")) {
				connection = init.getDbclusterConnection();
			} else {
				connection = init.getCommonConnection();
			}
			sr.sampleStart();// jmeter 开始统计响应时间标记
			if(testMode.equalsIgnoreCase("dataPrepare")){
				dataPrepare(connection);
			}else if (testMode.equals("batchInsert")) {
				batchTest(connection);
			} else if (testMode.equals("insert")) {
				insertTest(connection);
			} else if (testMode.equals("update")) {
				updateTest(connection);
			} else if (testMode.equals("selectByKey")) {
				selectByKeyTest(connection);
			} else if (testMode.equals("selectList")) {
				selectListTest(connection);
			} else if (testMode.equals("selectOrderBy")) {
				selectOrderByTest(connection);
			} else if (testMode.equals("selectGroupBy")) {
				selectGroupByTest(connection);
			} else if (testMode.equals("relationSelect")) {
				relationSelectTest(connection);
			}else if(testMode.equals("delete")){
				deleteTest(connection);
			}
			sr.sampleEnd();// jmeter 结束统计响应时间标记
			sr.setSuccessful(true);
		} catch (SQLException e) {
			sr.setSuccessful(false);
			e.printStackTrace();
		} finally {
			if (connection != null) {
				try {
					connection.close();
				} catch (SQLException e) {
				}
			}
		}
		return sr;
	}

	private void deleteTest(Connection connection) throws SQLException {
		PreparedStatement preparedStatement = connection
				.prepareStatement("delete from t_order  where order_id=?");
		try {
			long next = getRandomId();
			String orderId = "" + (330226190000000000l + next);
			preparedStatement.setString(1, orderId);
			int result = preparedStatement.executeUpdate();
				System.out.println("deleteTest:result:"
						+ result+",orderId:"+orderId);
		} finally {
			if (preparedStatement != null) {
				preparedStatement.close();
			}
		}
	}

	/**
	 * 数据准备
	 *
	 * @param connection
	 * @throws SQLException
	 */
	private void dataPrepare(Connection connection) throws SQLException {
		PreparedStatement preparedStatement = null;
		try {
			connection.setAutoCommit(false);
			preparedStatement = connection
					.prepareStatement("insert into t_order_item(item_id,order_id,item_name) values(?,?,?)");
			for (int i = 0; i < batchNum; i++) {
				String orderId = "" + (330226190000000000l + i);
				preparedStatement.setLong(1, ++executeTimes);
				preparedStatement.setString(2, orderId);
				preparedStatement.setString(3, "itemname" + getRandomId());
				preparedStatement.addBatch();
				if (i > 0 && i % DEFAULT_BATCH_SIZE == 0) {
					System.out.println("批量提交一次");
					preparedStatement.executeBatch();
				}
			}
			preparedStatement.executeBatch();
			connection.commit();
		} catch (SQLException e) {
			connection.rollback();
			throw e;
		}finally {
			if(preparedStatement!=null){
				preparedStatement.close();
			}
		}
	}

	/**
	 * 一个线程执行
	 * 
	 * @param connection
	 * @throws SQLException
	 */
	private void batchTest(Connection connection) throws SQLException {
		try {
			connection.setAutoCommit(false);
			PreparedStatement preparedStatement = connection
					.prepareStatement("insert into t_order(order_id,order_name,status) values(?,?,?)");
			for (int i = 0; i < batchNum; i++) {
				String orderId = "" + (330226190000000000l + i);
				preparedStatement.setString(1, orderId);
				preparedStatement.setString(2, "ordername" + i);
				preparedStatement.setString(3, "init");
				preparedStatement.addBatch();
				if (i > 0 && i % DEFAULT_BATCH_SIZE == 0) {
					preparedStatement.executeBatch();
				}
			}
			preparedStatement.executeBatch();
			preparedStatement.close();
			preparedStatement = connection
					.prepareStatement("insert into t_order_item(item_id,order_id,item_name) values(?,?,?)");
			long primaryValue = 0;
			for (int i = 0; i < batchNum/10; i++) {
				String orderId = "" + (330226190000000000l + i);
				for (int j = 0; j < 10; j++) {
					preparedStatement.setLong(1, ++primaryValue);
					preparedStatement.setString(2, orderId);
					preparedStatement.setString(3, "itemname" + i);
					preparedStatement.addBatch();
					if (primaryValue % DEFAULT_BATCH_SIZE == 0) {
						preparedStatement.executeBatch();
					}
				}
			}
			preparedStatement.executeBatch();
			preparedStatement.close();
			connection.commit();
		} catch (SQLException e) {
			connection.rollback();
			throw e;
		}
	}

	private void insertTest(Connection connection) throws SQLException {
		PreparedStatement preparedStatement = connection
				.prepareStatement("insert into t_order_item(item_id,order_id,item_name,ext1) values(?,?,?,?)");
		try {
			int next = executeTimes++;
			preparedStatement.setInt(1, RandomUtils.nextInt());
			String orderId = "" + (340226190000000000l + next);
			preparedStatement.setString(2, orderId);
			preparedStatement.setString(3, "insertName");
			preparedStatement.setString(4, BIGDATA);
			preparedStatement.executeUpdate();
		} finally {
			if (preparedStatement != null) {
				preparedStatement.close();
			}
		}

	}

	private void updateTest(Connection connection) throws SQLException {
		PreparedStatement preparedStatement = connection
				.prepareStatement("update t_order_item set item_name=? where order_id=?");
		try {
			preparedStatement.setString(1, "updateName");
			long next = getRandomId()/10;
			String orderId = ""
					+ (330226190000000000l + next);
			preparedStatement.setString(2, orderId);
			preparedStatement.executeUpdate();
		} finally {
			if (preparedStatement != null) {
				preparedStatement.close();
			}
		}

	}

	private void selectByKeyTest(Connection connection) throws SQLException {
		PreparedStatement preparedStatement = connection
				.prepareStatement("select * from t_order  where order_id=?");
		try {
			long next = getRandomId();
			String orderId = "" + (330226190000000000l + next);
			preparedStatement.setString(1, orderId);
			ResultSet rs = preparedStatement.executeQuery();
			if (rs.next()) {
				System.out.println("selectByKeyTest:order_id:"
						+ rs.getLong("order_id"));
			}else{
				System.out.println("none");
			}
			rs.close();
		} finally {
			if (preparedStatement != null) {
				preparedStatement.close();
			}
		}
	}

	private void selectListTest(Connection connection) throws SQLException {
		PreparedStatement preparedStatement = connection
				.prepareStatement("select * from t_order_item  where order_id=?");
		try {
			int next =  getRandomId()/10;
			String orderId = "" + (330226190000000000l + next);
			preparedStatement.setString(1, orderId);
			ResultSet rs = preparedStatement.executeQuery();
			if (rs.next()) {
				System.out.println("selectListTest:order_id:"
						+ rs.getLong("order_id"));
			}else{
				System.out.println("none");
			}
			rs.close();
		} finally {
			if (preparedStatement != null) {
				preparedStatement.close();
			}
		}
	}

	private void selectOrderByTest(Connection connection) throws SQLException {
		PreparedStatement preparedStatement = connection
				.prepareStatement("select * from t_order_item  where order_id=? order by item_id desc");
		try {
			long next = getRandomId()/10;
			String orderId = "" + (330226190000000000l + next);
			preparedStatement.setString(1, orderId);
			ResultSet rs = preparedStatement.executeQuery();
			if (rs.next()) {
				System.out.println("selectOrderByTest:order_id:"
						+ rs.getLong("order_id"));
			}else{
				System.out.println("none");
			}
			rs.close();
		} finally {
			if (preparedStatement != null) {
				preparedStatement.close();
			}
		}
	}

	/**
	 * 1个线程执行
	 * 
	 * @param connection
	 * @throws SQLException
	 */
	private void selectGroupByTest(Connection connection) throws SQLException {
		PreparedStatement preparedStatement = connection
				.prepareStatement("SELECT SUM(item_id) AS item_sum, order_id FROM t_order_item GROUP BY order_id ORDER BY item_sum DESC");
		try {
			ResultSet rs = preparedStatement.executeQuery();
			if (rs.next()) {
				System.out.println("selectGroupByTest:item_sum:"
						+ rs.getLong("item_sum"));
			}else{
				System.out.println("none");
			}
			rs.close();
		} finally {
			if (preparedStatement != null) {
				preparedStatement.close();
			}
		}
	}

	private void relationSelectTest(Connection connection) throws SQLException {
		String sql = "SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id = i.order_id"
				+ " WHERE o.order_id IN (?,?,?)  ORDER BY i.item_id DESC LIMIT 0, 10";
		PreparedStatement preparedStatement = connection.prepareStatement(sql);
		try {
			int randomScope = batchNum/10;
			int random1 = RandomUtils.nextInt(randomScope);
			int random2 = RandomUtils.nextInt(randomScope);
			int random3 = RandomUtils.nextInt(randomScope);
			preparedStatement
					.setString(1, "" + (330226190000000000l + random1));
			preparedStatement
					.setString(2, "" + (330226190000000000l + random2));
			preparedStatement
					.setString(3, "" + (330226190000000000l + random3));
			ResultSet rs = preparedStatement.executeQuery();
			if (rs.next()) {
				System.out.println("relationSelectTest:order_id:"
						+ rs.getLong("order_id"));
			}else{
				System.out.println("none");
			}
			rs.close();
		} finally {
			if (preparedStatement != null) {
				preparedStatement.close();
			}
		}
	}

	private void deleteOperate(String sql, Connection connection)
			throws SQLException {
		Statement statement = connection.createStatement();
		statement.execute(sql);
		statement.close();
	}

	public Arguments getDefaultParameters() {
		Arguments params = new Arguments();
		params.addArgument("isShard", "true");
		params.addArgument("testMode", "batchInsert");
		params.addArgument("batchNum", "100000");
		return params;
	}

	public static void main(String[] args) { // TODO Auto-generated method stub
		 Arguments params = new Arguments();
		 params.addArgument("isShard", "false");// 设置参数，并赋予默认值1
		 params.addArgument("testMode", "insert");// 设置参数，并赋予默认值1
		 params.addArgument("batchNum", "1000");// 设置参数，并赋予默认值2
		 JavaSamplerContext arg0 = new JavaSamplerContext(params);
		 DbclusterTest test = new DbclusterTest();
		 test.setupTest(arg0);
		 long startTime=System.currentTimeMillis();
		 test.runTest(arg0);
		 System.out.println(System.currentTimeMillis()-startTime);
		 test.teardownTest(arg0);

	}

	protected int getRandomId(){
		int temp = (int)(Math.random()*batchNum);
		return temp;
	}
}
